home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 301-325 / disk_319 / cnewssrc / cnews.src.lzh / relay / fileart.c < prev    next >
C/C++ Source or Header  |  1989-07-31  |  11KB  |  390 lines

  1. /*
  2.  * fileart - file an article, given its temporary file name and its headers
  3.  *
  4.  * It may be desirable to, some day, prevent cross-postings across
  5.  * "universes", where a universe might be "alt" or "comp.news".
  6.  *
  7.  * There are three classes of newsgroup for the purposes of filing:
  8.  * "wanted" (in the active file and missing the "x" flag);
  9.  * "not wanted" ("x"ed in active, or not in active and not matched by sys
  10.  *    file's subscription list for this machine), so ignore it; or
  11.  * "don't know it" (not in active and matched by subscription list,
  12.  *    so file the article in junk once, iff there are no good groups).
  13.  * junk *must* be in the active file or it's an error (ST_DROPPED),
  14.  * but junk may have an "x" flag to prevent filing.
  15.  *
  16.  * Use the active file 'x' flag to snuff groups quietly, even when your
  17.  * subscription list permits them, without filing in junk.
  18.  */
  19.  
  20. #ifdef DEBUG
  21. #  define STAT(x)    {    fprintf(stderr,"%s: %d, ",__FUNC__,__LINE__);\
  22.                         fprintf x;\
  23.                         fflush(stderr); }
  24. #else
  25. #  define STAT(x)
  26. #endif
  27.  
  28. #include <stdio.h>
  29. #include <errno.h>
  30. #ifndef AMIGA
  31. #  include <sys/types.h>
  32. #endif /* AMIGA */
  33.  
  34. #include "libc.h"
  35. #include "news.h"
  36. #include "config.h"
  37. #include "active.h"
  38. #include "mkdirs.h"
  39. #include "headers.h"
  40. #include "article.h"
  41. #include "history.h"
  42. #include "system.h"
  43.  
  44. #define JUNK     "junk"            /* lost+found pseudo-ng. */
  45. #define CONTROL "control"        /* control message pseudo-ng. */
  46.  
  47. static long artnum;            /* asgnartnum sets artnum */
  48. static int goodngs;            /* asgnartnum reads goodngs */
  49.  
  50. static boolean debug = NO;
  51.  
  52. /* imports from news */
  53. extern void prefuse();
  54.  
  55. /* forwards */
  56. FORWARD void asgnartnum(), gotgoodng(), mkjunklink(), mklinks();
  57. FORWARD boolean openorlink(), mkonelink(), tryartnum();
  58.  
  59. void
  60. filedebug(state)        /* set debugging state */
  61. boolean state;
  62. {
  63.     debug = state;
  64. }
  65.  
  66. /*
  67.  * File in the spool directory the article in art & fill in art->a_files.
  68.  * Generate Xref: header if needed (successfully cross-posted).
  69.  *
  70.  * If a_unlink is true, there is a temp file, so openfirst should
  71.  * be false, and vice versa.
  72.  *
  73.  * If openfirst (!art->a_unlink) is true, fill in a_tmpf with the name of
  74.  * the first link, fopen it (into art->a_artf), and make any remaining links.
  75.  * If openfirst is false, just make links to a_tmpf, which is already
  76.  * open as art->a_artf.  openfirst means "Newsgroups:" was seen in time.
  77.  */
  78.  
  79. void fileart(art)
  80. register struct article *art;
  81. {
  82.     register boolean openfirst = !art->a_unlink;
  83.     int junkgroups = 0;        /* count "junked" groups */
  84.     char artnumstr[MAXCOMP];    /* article number in ascii */
  85.  
  86.     if (art->a_filed)
  87.         return;            /* don't file twice */
  88.     artnum = 0;
  89.     goodngs = 0;
  90.  
  91.     STAT((stderr,"calling mklinks()\n"));
  92.     mklinks(art, openfirst, artnumstr, &junkgroups);
  93.  
  94.     STAT((stderr,"calling mkjunklink()\n"));
  95.     mkjunklink(art, openfirst, artnumstr, &junkgroups);
  96.  
  97.     STAT((stderr,"goodngs = %d\n", goodngs));
  98.     if (goodngs > 1 && art->a_artf != NULL)    /* cross-posted? */
  99.         emitxref(art);
  100. }
  101.  
  102. /*
  103.  * Store in spooldir.  Link temp file to spooldir/ng/article-number
  104.  * for each ng.  Control messages go in CONTROL, never in all.all.ctl.
  105.  */
  106.  
  107. STATIC void mklinks(art, openfirst, artnumstr, junkgroupsp)
  108. register struct article *art;
  109. boolean openfirst;
  110. char *artnumstr;
  111. int *junkgroupsp;
  112. {
  113.     register char *ngs, *ng;
  114.     register char *comma;
  115.  
  116.     ngs = (art->h.h_ctlcmd != NULL? CONTROL: art->h.h_ngs);
  117.     if (art->a_status&ST_REFUSED)
  118.         (void) fprintf(stderr,
  119.             "%s: mklinks called with ST_REFUSED set (can't happen)\n",
  120.             progname);
  121.     for (; ngs != NULL; ngs = comma) {
  122.         comma = index(ngs, NGSEP);
  123.         if (comma != NULL)
  124.             *comma = '\0';        /* will be restored below */
  125.         STAT((stderr,"calling realngname()\n"));
  126.         ng = realngname(ngs);
  127.         STAT((stderr,"  returned '%s'\n", ng));
  128.         if (ng == NULL)
  129.             ng = strsave(ngs);
  130.  
  131.         STAT((stderr,"calling asgnartnum()\n"));
  132.         asgnartnum(art, openfirst, ng, artnumstr);
  133.         /*
  134.          * If no such group in active or link failed, and the group
  135.          * wasn't 'x'ed in active, but our subscription list permits
  136.          * this group, then set flag to file it under "junk" later.
  137.          */
  138.         if ((artnum < 1 || art->a_status != ST_OKAY) &&
  139.                 art->a_status != ST_REFUSED &&
  140.                     ngmatch(oursys()->sy_ngs, ng)) {
  141.             STAT((stderr,"artnum = %d, ST_OKAY %c, ST_REFUSED %c\n",
  142.                 artnum,
  143.                 art->a_status == ST_OKAY ? 'T' : 'F',
  144.                 art->a_status == ST_REFUSED ? 'T' : 'F'));
  145.             ++*junkgroupsp;
  146.         }
  147.         /*
  148.          * If article # was assigned & link succeeded,
  149.          * update art->a_files list for history.
  150.          */
  151.         if (artnum >= 1 && art->a_status == ST_OKAY)
  152.             gotgoodng(art, ng, artnumstr);
  153.         free(ng);
  154.  
  155.         if (comma != NULL)
  156.             *comma++ = NGSEP;    /* step past comma */
  157.  
  158.         /* asgnartnum refused just this ng */
  159.         art->a_status &= ~ST_REFUSED;
  160.     }
  161. }
  162.  
  163. /*
  164.  * File once in "junk" iff no ngs were filed due to absence from
  165.  * active, but some were permitted by sys.  This will make one junk
  166.  * link, no matter how many bad groups, and only if all are bad
  167.  * (e.g. rec.drugs,talk.chew-the-fat).
  168.  */
  169.  
  170. STATIC void mkjunklink(art, openfirst, artnumstr, junkgroupsp)
  171. register struct article *art;
  172. boolean openfirst;
  173. char *artnumstr;
  174. int *junkgroupsp;
  175. {
  176.     if (*junkgroupsp > 0 && goodngs == 0) {    /* all groups were "junked"? */
  177.         asgnartnum(art, openfirst, JUNK, artnumstr);
  178.         if (artnum >= 1 && art->a_status == ST_OKAY) {
  179.             gotgoodng(art, JUNK, artnumstr);
  180.             art->a_status |= ST_JUNKED;
  181.         } else {
  182.             /*
  183.              * couldn't file article in junk.
  184.              * was JUNK not 'x'ed (i.e. doesn't exist)?
  185.              */
  186.             if (art->a_status != ST_REFUSED) {
  187.                 static boolean warned = NO;
  188.  
  189.                 art->a_status |= ST_REFUSED|ST_DROPPED;
  190.                 if (!warned) {
  191.                     warned = YES;
  192.                     (void) fprintf(stderr,
  193.                         "%s: no %s group\n", progname, JUNK);
  194.                 }
  195.             }
  196.             prefuse(art);
  197.             (void) printf("no known groups in `%s' and no `%s' group\n",
  198.                 art->h.h_ngs, JUNK);
  199.         }
  200.     } else if (goodngs == 0) {
  201.         extern boolean histreject;
  202.  
  203.         /*
  204.          * Groups were permitted by subscription list, but all
  205.          * were 'x'ed in active, or otherwise refused.
  206.          */
  207.         if (histreject)
  208.             history(art, NOLOG);
  209.         prefuse(art);
  210.         (void) printf("all groups `%s' excluded in active\n", art->h.h_ngs);
  211.         art->a_status |= ST_REFUSED;
  212.     }
  213. }
  214.  
  215. /*
  216.  * Append ng/artnumstr to art's list of files, and bump goodngs.
  217.  */
  218.  
  219. STATIC void gotgoodng(art, ng, artnumstr)
  220. struct article *art;
  221. char *ng, *artnumstr;
  222. {
  223.     ++goodngs;
  224.     histupdfiles(art, ng, artnumstr);
  225. }
  226.  
  227. /*
  228.  * Assign a permanent name and article number to the temporary name
  229.  * art->a_tmpf in newsgroup "ng" & store the ascii form of the article
  230.  * number into "artnumstr", returning the article number in "artnum".
  231.  *
  232.  * If openfirst is true and goodngs is zero, set inname to artname,
  233.  * fopen artname and store the result in art->a_artf.
  234.  */
  235.  
  236. STATIC void asgnartnum(art, openfirst, ng, artnumstr)
  237. struct article *art;
  238. boolean openfirst;                /* open first link? */
  239. register char *ng;                /* read-only */
  240. char *artnumstr;
  241. {
  242.     register char *slashng;            /* a group, slashed */
  243.  
  244.     /* field active 'x' flag: don't file this group, quietly */
  245.     if (unwanted(ng)) {
  246.         STAT((stderr,"unwanted(`%s') returned TRUE\n", ng));
  247.         artnum = -1;
  248.         art->a_status |= ST_REFUSED;
  249.         return;
  250.     }
  251.     slashng = strsave(ng);
  252.  
  253.     STAT((stderr,"calling mkfilenm(`%s')\n", slashng));
  254.     mkfilenm(slashng);            /* relative to spooldir */
  255.  
  256.     STAT((stderr,"calling nxtartnum(`%s')\n", ng));
  257.     while ((artnum = nxtartnum(ng)) >= 1) {
  258.         STAT((stderr,"nxtartnum(`%s') returned %d\n", ng, artnum));
  259.         if (tryartnum(art, openfirst, slashng, artnumstr))
  260.             break;
  261.     }
  262.     free(slashng);
  263. }
  264.  
  265. /*
  266.  * Construct a link name (slashng/artnum) for this article,
  267.  * and try to link art to it.
  268.  *
  269.  * We changed directory to spooldir in main(), so the generated name
  270.  * is relative to spooldir, therefore artname can be used as is.
  271.  *
  272.  * Return value is identical to mkonelink's.
  273.  */
  274.  
  275. STATIC boolean tryartnum(art, openfirst, slashng, artnumstr)
  276. register struct article *art;
  277. boolean openfirst;
  278. register char *slashng;
  279. char *artnumstr;            /* side-effect returned here */
  280. {
  281.     register char *artname;        /* article file name */
  282.     register boolean ret;
  283.  
  284.     (void) sprintf(artnumstr, "%ld", artnum);
  285.     artname = nemalloc((unsigned) (strlen(slashng) +
  286.         STRLEN(SFNDELIM) + strlen(artnumstr) + 1));
  287.     (void) strcpy(artname, slashng);
  288.     (void) strcat(artname, SFNDELIM);
  289.     (void) strcat(artname, artnumstr);
  290. #ifdef notdef
  291.     char *tartname = strsave(artfile(artname));
  292.     free(artname);
  293.     artname = tartname;
  294. #endif
  295.     STAT((stderr, "calling mkonelink(`%s')\n", artname));
  296.     ret = mkonelink(art, artname, openfirst);
  297.     free(artname);
  298.     return ret;
  299. }
  300.  
  301. /*
  302.  * Try to link art to artname.
  303.  *
  304.  * If the attempt fails, maybe some intermediate directories are missing,
  305.  * so create any missing directories and try again.  If the second attempt
  306.  * also fails, look at errno; if it is EEXIST, artname already exists
  307.  * (presumably because the active file is out of date, or the existing
  308.  * file is a directory such as net/micro/432), so indicate that higher
  309.  * levels should keep trying, otherwise we are unable to create the
  310.  * necessary directories, so complain and set bad status in art.
  311.  *
  312.  * Returns YES iff there is no point in trying to file this article again,
  313.  * usually because it has been successfully filed, but sometimes because
  314.  * the necessary directories cannot be made.
  315.  */
  316.  
  317. STATIC boolean mkonelink(art, artname, openfirst)
  318. register struct article *art;
  319. register char *artname;
  320. boolean openfirst;
  321. {
  322.     if (openorlink(artname, art, openfirst, goodngs))
  323.         return YES;
  324.     else {
  325.         STAT((stderr, "openorlink() failed\n"));
  326.         STAT((stderr, "calling mkdirs(`%s')\n", artname));
  327.         (void) mkdirs(artname, getuid(), getgid());
  328.  
  329.         STAT((stderr, "trying openorlink() again\n"));
  330.         if (openorlink(artname, art, openfirst, goodngs))
  331.             return YES;
  332.         else if (errno != EEXIST) {
  333.             warning("can't link to `%s'", artname);
  334.             art->a_status |= ST_DROPPED;
  335.             return YES;        /* hopeless - give up */
  336.         } else
  337.             return NO;
  338.     }
  339. }
  340.  
  341. /*
  342.  * Try to make a link of art (actually art->a_tmpf) to artname.
  343.  * If no links have been made yet, record and open artname iff no
  344.  * link yet exists to that name (by any file, to avoid overwriting
  345.  * existing articles, e.g. due to an out-of-date active file).
  346.  * If links already exist, try to make artname a link to the first link
  347.  * (art->a_tmpf).
  348.  *
  349.  * Liberally sprinkled with debugging output, as this is the heart
  350.  * of article filing.
  351.  */
  352.  
  353. STATIC boolean openorlink(artname, art, openfirst, goodngcnt)
  354. register char *artname;
  355. register struct article *art;
  356. boolean openfirst;            /* open art's first link? */
  357. int goodngcnt;                /* count of good news groups */
  358. {
  359.     register boolean worked;        /* open or link worked? */
  360.  
  361.     if (openfirst && goodngcnt == 0) {
  362.         if (debug)
  363.             (void) fprintf(stderr, "opening `%s'... ", artname);
  364.         nnfree(&art->a_tmpf);
  365.         art->a_tmpf = strsave(artname);
  366.         art->a_artf = fopenexcl(art->a_tmpf);
  367.         worked = art->a_artf != NULL;
  368.     } else {
  369.         if (debug)
  370.             (void) fprintf(stderr, "linking `%s' to `%s'... ",
  371.                 art->a_tmpf, artname);
  372.         worked = link(art->a_tmpf, artname) == 0;
  373.         if (!worked)
  374.             /*
  375.              * If art->a_tmpf really *is* a temporary name (because
  376.              * the whole header didn't fit in core), then this will
  377.              * produce a symbolic link to a non-existent name when
  378.              * art->a_tmpf is unlinked, which will be soon.
  379.              * Moral: don't run Eunice on your PDP-11.
  380.              */
  381.             worked = symlink(art->a_tmpf, artname) == 0;
  382.     }
  383.     if (debug)
  384.         if (worked)
  385.             (void) fprintf(stderr, "success.\n");
  386.         else
  387.             warning("failed.", "");
  388.     return worked;
  389. }
  390.